import express from 'express' // 引入 express
import proxy from 'express-http-proxy'
import { render } from './utils'
import { matchRoutes } from 'react-router-config'

import routes from '../routes'
import { getServerStore } from '../store'

const app = express() // 使用 express 创建应用
app.use(express.static('public')) // 使用中间件，当 express 创建的服务器发现你请求一个静态文件，就会帮你在根目录下的 public 目录中去找

// proxy 代理
// /api/news.json 客户端请求路径
// req.url = 'news.json'
// proxyReqPathResolver: /ssr/api/news.json  这个函数会返回的路径字符串
// http://47.95.113.63 + proxyReqPathResolver() 在服务器端请求的路径
// http://47.95.113.63/ssr/api/news.json
app.use('/api', proxy('http://47.95.113.63', {
  proxyReqPathResolver: function (req) {
    return '/ssr/api' + req.url
  }
}))

app.get('*', (req, res) => {
  const store = getServerStore(req)

  // 根据路由来向 store 中存储数据
  const matchedRoutes = matchRoutes(routes, req.path)
  console.log('req.path', req.path)
  console.log('matchedRoutes', matchedRoutes)

  // 让 matchRoutes 里所有的组件对应的 loadData 方法执行一次
  const promises = []
  matchedRoutes.forEach(item => {
    // 判断是否存在 loadData，因为有些路由能够被匹配，但是并不一定需要异步请求数据
    if (item.route.loadData) {
      const newPromise = new Promise((resolve, reject) => {
        // 让 promises 数组中的所有 `promise` 都变为 `fulfilled` 状态
        // 这样就可以使 `Promise.all()` 方法等待所有组件的 `promise` 加载完成后才执行后面 .`then()` 中的逻辑
        item.route.loadData(store).then(resolve).catch(resolve)
      })
      promises.push(newPromise)
    }
  })

  Promise.all(promises)
    .then(() => {
      const context = {css:[]}
      const html = render(req, store, routes, context)

      if(context.action === 'REPLACE'){
        res.redirect(301, context.url)
      }else if (context.NOT_FOUND) {
        res.status(404)
        res.send(html)
      }else{
        res.send(html)
      }
    })
    .catch(error => {
      new Error(error)
    })
}) // 当你访问这个应用的所有路径时，会发送一段文本

app.listen(3000, () => console.log('Example app listening on port 3000!')) // 让应用监听 3000 端口，当启动这个端口就会在终端显示 log 中的内容
